//
//  GraphTester.cpp
//  AdvPropTestsCpp
//
//  Created by Brian Bogard on 2/25/12.
//
//  --Revision History--
//  Harsh Vachhani on 03/04/12
//
//  Copyright 2012 ASU. All rights reserved.
//

#include "GraphTester.h"
#include <iostream>
using namespace std;

GraphTester::GraphTester( boost::shared_ptr< Graph > _graphObj,
                          float _activeEdgeProb, 
                          int _initRedSelect, 
                          GraphTester::SELECT_ALG _redSelectArg, 
                          int _numberOfGraphs,
                          int _maxPropagationDist):
    m_baseGraph( _graphObj ),
    m_graphInstances( _numberOfGraphs ),
    m_initialRedSelection( _initRedSelect ),
    m_activeEdgeProb( _activeEdgeProb ),
    m_redSelectionAlg( _redSelectArg ),
    //Shahrzad
    m_maxPropagationDist(_maxPropagationDist)
{}

boost::unordered_map< int, double > GraphTester::makeFirstSelection( boost::shared_ptr< Graph > _graphInstance, GraphTester::SELECT_ALG _selectionAlg )
{
    boost::unordered_map< int, double > selectionAlgResults;
//Shahrzad changed
    if( _selectionAlg == CLOSENESS_CENTRALITY )
    {
    	selectionAlgResults = Graph::closenessCentralityList( _graphInstance );
//        selectionAlgResults = Graph::degreeCentralityList( _graphInstance );
    }
    else if( _selectionAlg == DEGREE_CENTRALITY )
    {
    	 selectionAlgResults = Graph::degreeCentralityList( _graphInstance );
//        selectionAlgResults = Graph::closenessCentralityList( _graphInstance );
    }
    else
    {
        cerr << "Cannot recognize selection algorithm: " << endl;
    }
    
    return selectionAlgResults;
}

int GraphTester::makeSecondSelections( vector< boost::shared_ptr< Graph > > _graphInstances, vector< nodeValTuple > _nodeList, Node::COLOR _nodeColor )
{
    Graph graphInstance;
   	int nodeID = boost::get<0>( _nodeList[ 0 ] );

   	//Shahrzad-debug
    cerr<<"Node "<<nodeID<<" becomes Blue and its propDiff is "<< boost::get<1>( _nodeList[ 0 ] )<<endl;
    vector <boost::shared_ptr<Graph>>::iterator It;
    for(It=_graphInstances.begin(); It!=_graphInstances.end(); ++It)
    {
    	(*It)->setNodeColor(nodeID, _nodeColor);
    }
    // Code not compiling due to gcc dependency
    // replacing with above loop
	/*
    for( Graph graphInstance: _graphInstances )
    {
        graphInstance.setNodeColor( nodeID, _nodeColor );
    }
	*/
    return boost::get<1>( _nodeList[ 0 ] );
}


void GraphTester::setupFirstSelections( vector< boost::shared_ptr< Graph > > _graphInstances,
                                        vector< boost::tuple< int, double > > _nodeList, 
                                        int _numSelected, 
                                        Node::COLOR _nodeColor )
{
    for( int nodeNum = 0; nodeNum < _numSelected; ++nodeNum )
    {

    	vector <boost::shared_ptr<Graph>>::iterator It;
    	for(It=_graphInstances.begin(); It!=_graphInstances.end(); ++It)
    	{
    		(*It)->setNodeColor(boost::get<0>( _nodeList[ nodeNum ] ), _nodeColor);
    	}
    	// Code not compiling due to gcc dependency
    	// replacing with above loop
    	/*
        for( Graph graphInst: _graphInstances )
        {
            graphInst.setNodeColor( boost::get<0>( _nodeList[ nodeNum ] ), _nodeColor );
        }
		*/
    }
}

boost::unordered_map< int, double > GraphTester::makeSecondSelection( boost::shared_ptr< Graph > _graphInstance, Node::COLOR _nodeColor )
{
    boost::unordered_map< int, double > selectionResults;
    double propDiff;
    
    for( unsigned int nodeIndex = 0; nodeIndex < _graphInstance->m_nodeMap.size(); ++nodeIndex )
    {
        cerr << "Starting to set node color in makeSecondSelection" << endl;
        if( _graphInstance->getNodeColor( nodeIndex ) != Node::WHITE )
        {
        	//Shahrzad: For these nodes the bluenodeVal remains zero
        	//so initially it will be greater than the values of other nodes.
        	//Then one of these nodes will be selected to be the most influential while we need
        	//to select one of the white nodes
        	//I think if we assign a vey small value to already colored nodes like -n it becomes correct
        	//or in function makeSecondSelections instead of first element of sorted list we select the first white element of the sorted list
        	//I just make the change to this part (It should be fine)
        	selectionResults[ nodeIndex ] = 0.0-(_graphInstance->m_nodeMap.size());
        	  cerr << "Node " << nodeIndex << " propDiff of " << selectionResults[ nodeIndex ] << endl;
        	continue;
        }
        
        cerr << "setNodeColor" << endl;
        cerr << "If node "<<nodeIndex<<" becomes BLUE " << endl;
        _graphInstance->setNodeColor( nodeIndex , _nodeColor );
        cerr << "going into propagate..." << endl;
        propDiff = Graph::propagate( _graphInstance, m_maxPropagationDist );
        cerr << "Node " << nodeIndex << " propDiff of " << propDiff << endl;
        selectionResults[ nodeIndex ] = propDiff;
        _graphInstance->resetNodeColor( nodeIndex );
    }
    
    return selectionResults;
}

int GraphTester::runTests()
{
	cerr << "Inside run tests" << endl;
	// First, let's make an array with a bunch of graph instances.
	vector< boost::shared_ptr< Graph > > graphInstances;

	for( int index = 0; index < m_graphInstances; ++index )
	{
		boost::shared_ptr< Graph > tempGraph( new Graph( *m_baseGraph ) );
		Graph::initializeActiveEdges( tempGraph, m_activeEdgeProb );
		graphInstances.push_back( tempGraph );
	}

	cout << "Finished creating the graph copies, now initializing the node values" << endl;
	// Let's initialize values to select red nodes
	boost::unordered_map< int, double > nodeValMap;
	for(unsigned int nodeNum = 0; nodeNum < m_baseGraph->m_nodeMap.size(); ++nodeNum )
	{
		nodeValMap[ nodeNum ] = 0.0;
	}
	cout << "Finished initializing the node values, now getting most valuable red selections" << endl;
    // Let's add up the value for all graph instances
    vector <boost::shared_ptr<Graph>>::iterator It;
    for(It=graphInstances.begin(); It!=graphInstances.end(); ++It)
    {
    	boost::unordered_map< int, double > selectionResults = makeFirstSelection( *It, m_redSelectionAlg );
   		for( unsigned int nodeNum = 0; nodeNum < m_baseGraph->m_nodeMap.size(); ++nodeNum )
		{
			nodeValMap[ nodeNum ] = nodeValMap[ nodeNum ] + selectionResults[ nodeNum ];

		}
    }
    //Shahrzad-debug
    cerr<<"Node values:"<<endl;
    for( unsigned int nodeNum = 0; nodeNum < m_baseGraph->m_nodeMap.size(); ++nodeNum )
    		{
    			cerr<< nodeNum << ","<< nodeValMap[ nodeNum ]<<endl;
    		}

    // Code not compiling due to gcc dependency
    // replacing with above loop
    /*
    for( Graph graphInstance: graphInstances )
    {
        boost::unordered_map< int, double > selectionResults = makeFirstSelection( graphInstance, m_redSelectionAlg );
        
        for( unsigned int nodeNum = 0; nodeNum < m_baseGraph.m_nodeMap.size(); ++nodeNum )
        {
            nodeValMap[ nodeNum ] = nodeValMap[ nodeNum ] + selectionResults[ nodeNum ];
        }
    }
	*/
    cout << "Finished getting the most valuable red selection, now sorting nodes" << endl;
    // Now we need to find which node is deemed the most "valuable"
    vector< boost::tuple< int, double > > nodeList;
    
    for( unsigned int nodeNum = 0; nodeNum < m_baseGraph->m_nodeMap.size(); ++nodeNum )
    {
        nodeList.push_back( boost::make_tuple( nodeNum, nodeValMap[ nodeNum ] ) );
    }

    std::sort( nodeList.begin(), nodeList.end(), compareNodeVals() );
	cout << "Setting up the first red selections" << endl;
	setupFirstSelections( graphInstances, nodeList, m_initialRedSelection, Node::RED );

	//Shahrzad-debug
	//I think the sort function returns the values in increasing order;
	//so the selected nodes are not the correct one
	//I changed compareNodeVals(); now it works fine
	vector <boost::shared_ptr<Graph>>::iterator Itt;
	for(Itt=graphInstances.begin(); Itt!=graphInstances.end(); ++Itt)
	{
		for(unsigned int nodeNum = 0; nodeNum < (*Itt)->m_nodeMap.size(); ++nodeNum )
	    	{
	    		cerr<<"node "<<nodeNum<<" is "<<(*Itt)->getNodeColor(nodeNum)<<endl;
	    	}
	}

	cout << "Now we can deal with the blue nodes" << endl;
    // Ok, time for the blue node stuff
    int blueNodeDiff = 0;
    //Shahrzad
    int numOfBlue = 0;
    while( blueNodeDiff <= 0 )
    {
        //Old Shahrzad: Shouldn't the second value in blueNodeValMap be double? It shows the difference between the expected number of Blue nodes and expected number of red nodes
        boost::unordered_map< int, double > blueNodeValMap;
        for( unsigned int nodeNum = 0; nodeNum < m_baseGraph->m_nodeMap.size(); ++nodeNum )
        {

            blueNodeValMap[ nodeNum ] = 0.0;
        }

        cout << "Set all blue nodes to 0.0, now trying to figure out how many blue nodes we need" << endl;

        // For each of the graph instances, we need to find the diff in red and blue nodes after propagation
		for( unsigned int index = 0; index < graphInstances.size(); ++index )
		{
			cerr << "Second selection for blue" << endl;
			boost::unordered_map< int, double > selectionResults = makeSecondSelection( graphInstances[ index ], Node::BLUE );
			for( unsigned int nodeNum = 0; nodeNum < m_baseGraph->m_nodeMap.size(); ++nodeNum )
			{
				blueNodeValMap[ nodeNum ] = blueNodeValMap[ nodeNum ] + selectionResults[ nodeNum ];
			}
		}


        /*
        // For each of the graph instances, we need to find the diff in red and blue nodes after propagation
        vector <boost::shared_ptr<Graph>>::iterator It;
        for(It=graphInstances.begin(); It!=graphInstances.end(); ++It)
		{
            cerr << "Second selection for blue" << endl;
        	boost::unordered_map< int, double > selectionResults = makeSecondSelection( *It, Node::BLUE );
			for( unsigned int nodeNum = 0; nodeNum < m_baseGraph->m_nodeMap.size(); ++nodeNum )
			{
				blueNodeValMap[ nodeNum ] = blueNodeValMap[ nodeNum ] + selectionResults[ nodeNum ];
			}
		}

		 * Since the foreach in below code is not supported by gcc4.5, normal forloop
		 * replaces this code (above)
        for( Graph graphInstance: graphInstances )
        {
            boost::unordered_map< int, double > selectionResults = makeSecondSelection( graphInstance, Node::BLUE );
            for( unsigned int nodeNum = 0; nodeNum < m_baseGraph.m_nodeMap.size(); ++nodeNum )
            {
                blueNodeValMap[ nodeNum ] = blueNodeValMap[ nodeNum ] + selectionResults[ nodeNum ];
            }
        }
		*/
       cerr << "Now we have to sort the data for blue" << endl;
        // Now we have to sort the data
        vector< nodeValTuple > blueNodeList;
        for( unsigned int nodeNum = 0; nodeNum < m_baseGraph->m_nodeMap.size(); ++nodeNum )
        {
            blueNodeList.push_back( boost::make_tuple( nodeNum, blueNodeValMap[ nodeNum ] ) );
        }
        std::sort( blueNodeList.begin(), blueNodeList.end(), compareNodeVals() ); 
        
        blueNodeDiff = makeSecondSelections( graphInstances, blueNodeList, Node::BLUE );
        numOfBlue+=1;
 //       cerr << "blueNodeDiff: " << blueNodeDiff << endl;
    }
    //Shahrzad: Shouldn't it return the number of blue nodes, which is equal to the number of iterations in while loop?
    //return blueNodeDiff;
        return numOfBlue;
}




